Skip to content

Conversation

@vogella
Copy link
Member

@vogella vogella commented Nov 14, 2025

This commit adds functionality to the z.ex.search plugin:

  • New toolbar button with PDF icon in the main Eclipse toolbar
  • Button executes ~/git/content/_scripts/buildRCPScript.sh when pressed
  • BuildRCPScriptHandler class handles script execution in background thread
  • Shows success/error dialog with script output
  • Uses Eclipse 3.x API (org.eclipse.ui.menus) for toolbar contribution

Note: The hard-coded script path (~/git/content/_scripts/buildRCPScript.sh) is intentional and points to a specific location in the user's home directory.

Files added:

  • z.ex.search/src/z/ex/search/BuildRCPScriptHandler.java
  • z.ex.search/icons/pdf.svg

Files modified:

  • z.ex.search/plugin.xml (added command and toolbar contribution)
  • z.ex.search/build.properties (included icons directory)

This commit adds functionality to the z.ex.search plugin:
- New toolbar button with PDF icon in the main Eclipse toolbar
- Button executes ~/git/content/_scripts/buildRCPScript.sh when pressed
- BuildRCPScriptHandler class handles script execution in background thread
- Shows success/error dialog with script output
- Uses Eclipse 3.x API (org.eclipse.ui.menus) for toolbar contribution

Note: The hard-coded script path (~/git/content/_scripts/buildRCPScript.sh)
is intentional and points to a specific location in the user's home directory.

Files added:
- z.ex.search/src/z/ex/search/BuildRCPScriptHandler.java
- z.ex.search/icons/pdf.svg

Files modified:
- z.ex.search/plugin.xml (added command and toolbar contribution)
- z.ex.search/build.properties (included icons directory)
@gemini-code-assist
Copy link

Summary of Changes

Hello @vogella, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the z.ex.search plugin by integrating a new user interface element: a toolbar button. This button provides a convenient way for users to trigger a predefined shell script, specifically designed for building RCP applications. The implementation ensures a smooth user experience by executing the script asynchronously and providing clear feedback on its outcome, thereby streamlining a common development workflow.

Highlights

  • New Toolbar Button: A new button with a PDF icon has been added to the main Eclipse toolbar within the z.ex.search plugin.
  • Script Execution: This new toolbar button is configured to execute a specific shell script located at ~/git/content/_scripts/buildRCPScript.sh.
  • Background Processing: A new Java class, BuildRCPScriptHandler, has been introduced to manage the script's execution in a background thread, preventing the UI from freezing.
  • User Feedback: The handler provides informative dialogs to the user, indicating either the successful completion of the script or detailing any errors encountered, including the script's output.
  • Eclipse API Usage: The toolbar contribution leverages the org.eclipse.ui.menus API, which is part of the Eclipse 3.x platform.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request successfully adds a new toolbar button to execute a build script. The implementation correctly uses a background thread to prevent UI freezes. However, there are several opportunities for improvement to align with Eclipse development best practices. My review includes suggestions to use the Eclipse Jobs API instead of a raw thread for better IDE integration, improve path construction for platform independence, clean up logging and imports, and enhance UI feedback for script failures. Applying these changes will increase the robustness and maintainability of the new functionality.

Comment on lines 38 to 85
Thread scriptThread = new Thread(() -> {
try {
ProcessBuilder pb = new ProcessBuilder(SCRIPT_PATH);
pb.directory(scriptFile.getParentFile());
pb.redirectErrorStream(true);

Process process = pb.start();

// Read and display output
StringBuilder output = new StringBuilder();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
System.out.println(line);
}
}

int exitCode = process.waitFor();

final String message;
if (exitCode == 0) {
message = "RCP build script executed successfully.";
} else {
message = "RCP build script failed with exit code: " + exitCode +
"\n\nOutput:\n" + output.toString();
}

Display.getDefault().asyncExec(() -> {
MessageDialog.openInformation(
Display.getDefault().getActiveShell(),
"Build RCP Script",
message
);
});

} catch (IOException e) {
showError("Error executing script: " + e.getMessage());
} catch (InterruptedException e) {
showError("Script execution interrupted: " + e.getMessage());
Thread.currentThread().interrupt();
}
});

scriptThread.setDaemon(true);
scriptThread.start();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

While using a separate Thread prevents blocking the UI, the recommended approach in Eclipse plugin development is to use the Jobs API (org.eclipse.core.runtime.jobs.Job). Jobs provide better integration with the Eclipse UI, including progress reporting in the Progress view, cancellation support, and proper scheduling. Refactoring this to a Job would make the implementation more robust and provide a better user experience.

Here is a basic structure for converting this to a Job:

Job job = new Job("Building RCP") {
    @Override
    protected IStatus run(IProgressMonitor monitor) {
        // Your script execution logic here...
        // You can report progress via the monitor.
        // Show dialogs using Display.getDefault().asyncExec(...)
        // Return Status.OK_STATUS for success, or an error status.
        return Status.OK_STATUS;
    }
};
job.setUser(true); // Shows the job in the UI
job.schedule();

Comment on lines 11 to 15
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.handlers.HandlerUtil;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The imports org.eclipse.core.runtime.IStatus, org.eclipse.core.runtime.Status, and org.eclipse.ui.handlers.HandlerUtil are not used and should be removed to keep the code clean.

Suggested change
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;

Comment on lines 20 to 21
private static final String SCRIPT_PATH = System.getProperty("user.home") +
"/git/content/_scripts/buildRCPScript.sh";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using + to concatenate path components with a hardcoded separator / is not platform-independent. It's better to use java.nio.file.Paths.get() to construct the path. This makes the code cleaner and more robust across different operating systems. You will need to add import java.nio.file.Paths; for this change.

private static final String SCRIPT_PATH = java.nio.file.Paths.get(System.getProperty("user.home"), "git", "content", "_scripts", "buildRCPScript.sh").toString();

String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
System.out.println(line);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Printing script output directly to System.out can clutter the console and is generally not recommended for production code. For proper logging, consider using the Eclipse logging framework. Since the output is already collected and shown in the dialog on failure, this line seems redundant and can be removed.

Comment on lines 59 to 73
final String message;
if (exitCode == 0) {
message = "RCP build script executed successfully.";
} else {
message = "RCP build script failed with exit code: " + exitCode +
"\n\nOutput:\n" + output.toString();
}

Display.getDefault().asyncExec(() -> {
MessageDialog.openInformation(
Display.getDefault().getActiveShell(),
"Build RCP Script",
message
);
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When the script execution fails, an information dialog (MessageDialog.openInformation) is shown. It would be more appropriate and consistent with the showError method to use an error dialog (MessageDialog.openError) to clearly signal to the user that something went wrong.

final boolean success = exitCode == 0;

				Display.getDefault().asyncExec(() -> {
					if (success) {
						MessageDialog.openInformation(
							Display.getDefault().getActiveShell(),
							"Build RCP Script",
							"RCP build script executed successfully."
						);
					} else {
						String message = "RCP build script failed with exit code: " + exitCode +
								"\n\nOutput:\n" + output.toString();
						MessageDialog.openError(
							Display.getDefault().getActiveShell(),
							"Build RCP Script Error",
							message
						);
					}
				});

This commit addresses code review feedback and implements Eclipse best practices:

1. Replace raw Thread with Eclipse Jobs API (org.eclipse.core.runtime.jobs.Job)
   - Better integration with Eclipse UI progress reporting
   - Shows job in Progress view with 'Building RCP' label
   - Support for cancellation via IProgressMonitor
   - Proper status reporting (OK, ERROR, CANCEL)

2. Use Paths.get() for platform-independent path construction
   - Replaced string concatenation with java.nio.file.Paths
   - More robust across different operating systems

3. Remove unused imports
   - Removed org.eclipse.ui.handlers.HandlerUtil (not used)

4. Remove console logging
   - Removed System.out.println() calls (redundant)
   - Output is already collected and shown in dialogs

5. Use appropriate dialog types
   - Success: MessageDialog.openInformation
   - Failure: MessageDialog.openError (changed from openInformation)
   - More consistent with Eclipse UI conventions

These improvements enhance robustness, maintainability, and user experience
by following Eclipse plugin development best practices.
When the RCP build script executes successfully, the user is now prompted
with a question dialog asking if they want to open the generated PDF file.

Changes:
- Success dialog changed from openInformation to openQuestion
- Adds prompt: "Do you want to open the PDF file?"
- New openPdfFile() method to handle PDF opening
- Uses SWT Program.launch() to open PDF with system default application
- PDF path hard-coded to ~/git/content/output.pdf (intentional)
- Validates PDF file exists before attempting to open
- Shows error if PDF not found or no PDF viewer associated

User can now:
1. Click "Open" to view the PDF in their system's default PDF viewer
2. Click "Cancel" to dismiss the dialog without opening the file

Note: Both the script path and PDF output path are intentionally hard-coded
to specific locations in the user's home directory.
@vogella
Copy link
Member Author

vogella commented Nov 14, 2025

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a new toolbar button to execute a build script. The implementation correctly uses an Eclipse Job to run the script in the background, preventing UI freezes. The code is generally well-structured. I have a few suggestions to improve flexibility, correctness, and user experience. My main points are about making the hardcoded script paths configurable, ensuring the background process is terminated reliably on cancellation, and avoiding redundant error notifications to the user.

Comment on lines 23 to 26
private static final String SCRIPT_PATH = Paths.get(System.getProperty("user.home"),
"git", "content", "_scripts", "buildRCPScript.sh").toString();
private static final String PDF_OUTPUT_PATH = Paths.get(System.getProperty("user.home"),
"git", "content", "output.pdf").toString();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The script path and PDF output path are hardcoded. While the PR description mentions this is intentional, it severely limits the plugin's flexibility and makes it difficult for other users to adapt it to their environment. A better approach would be to make these paths configurable via the Eclipse preference store (IPreferenceStore). This would allow users to set their own paths in the plugin's preference page without needing to modify the source code.

while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
if (monitor.isCanceled()) {
process.destroy();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The process.destroy() method sends a standard termination signal, which the process can choose to ignore. When a user cancels a job, they usually expect it to stop immediately. Using process.destroyForcibly() is more reliable for ensuring the process is terminated upon cancellation.

Suggested change
process.destroy();
process.destroyForcibly();

return Status.OK_STATUS;

} catch (IOException e) {
showError("Error executing script: " + e.getMessage());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Calling showError() here in addition to returning an error IStatus can lead to duplicate error notifications for the user (one from your dialog, another from the Eclipse Jobs UI). It's better to rely on the returned IStatus to report the error. The message from the status will be shown to the user in the Progress view.

Suggested change
showError("Error executing script: " + e.getMessage());
// showError("Error executing script: " + e.getMessage());

return new Status(IStatus.ERROR, "z.ex.search",
"Error executing script", e);
} catch (InterruptedException e) {
showError("Script execution interrupted: " + e.getMessage());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the IOException handler, calling showError() here is redundant because Status.CANCEL_STATUS will notify the user of the cancellation via the Eclipse Jobs UI. Removing this call will prevent duplicate notifications.

Suggested change
showError("Script execution interrupted: " + e.getMessage());
// showError("Script execution interrupted: " + e.getMessage());

This commit addresses code review feedback to improve flexibility and robustness:

1. Make paths configurable via Eclipse preferences (MAJOR IMPROVEMENT)
   - Created PreferenceConstants class with default paths
   - Created PreferenceInitializer for default preference values
   - Created BuildScriptPreferencePage for user configuration
   - Registered preference page and initializer in plugin.xml
   - Users can now customize script and PDF paths via:
     Window > Preferences > Build Script
   - Defaults to original hard-coded paths for backward compatibility

2. Improve process termination on cancellation
   - Changed process.destroy() to process.destroyForcibly()
   - Ensures immediate termination when user cancels the job
   - More reliable than standard destroy() which can be ignored

3. Remove redundant error notifications
   - Removed showError() calls in IOException and InterruptedException handlers
   - IStatus errors are automatically shown in Eclipse Jobs UI
   - Prevents duplicate error dialogs for better UX

4. Code improvements
   - Removed unused java.nio.file.Paths import (no longer needed)
   - Read paths from preference store in execute() and openPdfFile()
   - Maintain backward compatibility with existing default paths

Benefits:
- Plugin is now flexible and reusable for different environments
- Better user control without modifying source code
- More reliable cancellation handling
- Cleaner error reporting without duplication
- Follows Eclipse plugin development best practices

Files added:
- z.ex.search/src/z/ex/search/PreferenceConstants.java
- z.ex.search/src/z/ex/search/PreferenceInitializer.java
- z.ex.search/src/z/ex/search/BuildScriptPreferencePage.java

Files modified:
- z.ex.search/src/z/ex/search/BuildRCPScriptHandler.java
- z.ex.search/plugin.xml
This commit replaces all MessageDialog popups with the modern Eclipse
Notification API for a better user experience.

Changes:
1. Success notification with interactive "Open PDF" button
   - NotificationPopup appears in bottom-right corner
   - User can click "Open PDF" button directly in notification
   - Non-blocking, allows continued work while notification is visible

2. Error notifications for build failures
   - Shows error message in notification popup
   - Truncates long error messages (>300 chars) for readability
   - Consistent with modern Eclipse UI patterns

3. Updated MANIFEST.MF
   - Added org.eclipse.jface dependency for NotificationPopup API

4. Improved user experience
   - Non-modal notifications don't block workflow
   - Notifications auto-dismiss after timeout
   - Action buttons directly in notification
   - Modern, consistent with Eclipse platform

Implementation:
- Uses NotificationPopup.forDisplay() fluent API
- WidgetFactory for creating notification content
- GridLayout for organizing notification widgets
- onSelect() handlers for interactive buttons

Benefits:
- Less intrusive than modal dialogs
- Users can continue working while notification is visible
- Better integration with Eclipse UI conventions
- More professional, modern appearance

Files modified:
- z.ex.search/src/z/ex/search/BuildRCPScriptHandler.java
- z.ex.search/META-INF/MANIFEST.MF
The previous commit used NotificationPopup API which is not available
in the target platform, causing build failures.

Changes:
- Reverted from NotificationPopup to MessageDialog
- Removed org.eclipse.jface dependency from MANIFEST.MF
- Renamed methods to showSuccessDialog() and showErrorDialog()
- Removed unnecessary imports (WidgetFactory, SWT, Composite)
- Kept all code review improvements:
  * Configurable preferences ✓
  * process.destroyForcibly() for cancellation ✓
  * No duplicate error notifications ✓
  * Eclipse Jobs API ✓

User experience remains the same:
- Success: Question dialog with "Open" and "Cancel" buttons
- Failure: Error dialog with exit code and output
- All paths configurable via preferences

This resolves the build failure while maintaining all improvements.
@vogella vogella merged commit 4f1dd47 into main Nov 14, 2025
1 check passed
@vogella vogella deleted the claude/add-search-plugin-button-019B21ZEGm95jTUDexTzQXDG branch November 14, 2025 12:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants